package com.sdy.configcenter.biz.service.impl;

import com.sdy.common.utils.StringUtil;
import com.sdy.configcenter.biz.constants.RedisConstants;
import com.sdy.configcenter.biz.model.WxOaAccessToken;
import com.sdy.configcenter.biz.mapper.WxOaAccessTokenMapper;
import com.sdy.configcenter.biz.service.WxOaAccessTokenService;
import com.sdy.configcenter.biz.utils.HttpReqUtil;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.sdy.mvc.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zzq
 * @since 2020-05-27
 */
@Slf4j
@Service
public class WxOaAccessTokenServiceImpl extends BaseServiceImpl<WxOaAccessToken> implements WxOaAccessTokenService {
    @Autowired
    private WxOaAccessTokenMapper wxOaAccessTokenMapper;

    @Override
    public WxOaAccessToken getByAppid(String appid) {
        return lambdaQuery()
                .eq(WxOaAccessToken::getAppid, appid)
                .one();
    }

    @Override
    public void refreshGetAccessToken(WxOaAccessToken wxOaAccessToken) {
        try {
            Pair<String, Integer> at = getOaAccessToken(wxOaAccessToken.getAppid(), wxOaAccessToken.getAppsecret());
            lambdaUpdate()
                    .eq(WxOaAccessToken::getId, wxOaAccessToken.getId())
                    .set(WxOaAccessToken::getAccessToken, at.getKey())
                    .set(WxOaAccessToken::getAccessTokenExpire, new Date(System.currentTimeMillis() + (at.getValue() - 200) * 1000))
                    .update();
        } catch (Exception e) {
            log.error("", e);
        }
    }

    @Override
    public void refreshGetJsApiTicket(WxOaAccessToken wxOaAccessToken) {
        try {
            Pair<String, Integer> at = getOaJsApiTicket(wxOaAccessToken.getAccessToken());
            lambdaUpdate()
                    .eq(WxOaAccessToken::getId, wxOaAccessToken.getId())
                    .set(WxOaAccessToken::getJsApiTicket, at.getKey())
                    .set(WxOaAccessToken::getJsApiTicketExpire, new Date(System.currentTimeMillis() + (at.getValue() - 200) * 1000))
                    .update();
        } catch (Exception e) {
            log.error("", e);
        }
    }

    public interface WxApi {
        String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${SECRET}";
        String JS_API_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${ACCESS_TOKEN}&type=jsapi";
    }

    private Pair<String, Integer> getOaAccessToken(String appid, String appsecret) {
        String accessToken;
        String api = WxApi.ACCESS_TOKEN.replace("${APPID}", appid).replace("${SECRET}", appsecret);
        log.warn("getOaAccessToken:{}",api);
        String resp = HttpReqUtil.get(api, StandardCharsets.UTF_8.name(), 2000, null);
        Map<String, Object> m = JsonUtil.fromJson(resp, HashMap.class);
        checkWxRespStatus(m);
        accessToken = (String) m.get("access_token");
        int expireIn = (Integer) m.get("expires_in");
        log.info("获取微信access_token：{}", accessToken);
        return Pair.of(accessToken, expireIn);
    }

    private Pair<String, Integer> getOaJsApiTicket(String accessToken) {
        String jsApiTicket;
        String api = WxApi.JS_API_TICKET.replace("${ACCESS_TOKEN}", accessToken);
        log.warn("getOaJsApiTicket:{}",api);
        String resp = HttpReqUtil.get(api, StandardCharsets.UTF_8.name(), 2000, null);
        Map<String, Object> m = JsonUtil.fromJson(resp, HashMap.class);
        checkWxRespStatus(m);
        jsApiTicket = (String) m.get("ticket");
        int expireIn = (Integer) m.get("expires_in");
        log.info("获取微信js_api_ticket：{}", jsApiTicket);
        return  Pair.of(jsApiTicket, expireIn);
    }

    private void checkWxRespStatus(Map<String, Object> m) {
        log.warn("error:{}",m);
        if (!m.containsKey("errcode") || (Integer) m.get("errcode") == 0) {
            return;
        }
        throw new RuntimeException(m.get("errmsg") + "(" + m.get("errcode") + ")");
    }
}
